const EventEmitter = require("events");
const http = require("http");
const context = require("./context");
const request = require("./request");
const response = require("./response");
const Stream = require("stream");
module.exports = class Application extends EventEmitter {
  constructor() {
    // 每个应用之间 这个context 应该不是一个, 通过Object.create 每次创建应用都创建一个全新的对象来，可以找到扩展的方法， 但是新增属性时不会影响此方法
    super();
    this.context = Object.create(context);
    this.request = Object.create(request);
    this.response = Object.create(response);
    this.middlewares = [];
  }
  use(fn) {
    this.middlewares.push(fn);
  }
  createContext(req, res) {
    let ctx = Object.create(this.context);
    let request = Object.create(this.request);
    let response = Object.create(this.response);
    ctx.req = req;
    ctx.res = res;
    ctx.request = request;
    ctx.response = response;
    ctx.request.req = req;
    ctx.response.res = res;
    return ctx;
  }
  compose(ctx) {
    let middlewares = this.middlewares;
    // 中间件的组合
    let idx = -1;
    function dispatch(i) {
      if (i == idx) return Promise.reject(new Error("多次调用了next 不合法"));
      if (i === middlewares.length) return Promise.resolve();
      let middleware = middlewares[i];
      idx = i;
      try {
        return Promise.resolve(middleware(ctx, () => dispatch(i + 1)));
      } catch (e) {
        return Promise.reject(e);
      }
    }
    return dispatch(0);
  }
  handleRequest = (req, res) => {
    let ctx = this.createContext(req, res);
    // 处理请求
    res.statusCode = 404; // 先默认给了404
    this.compose(ctx)
      .then(() => {
        // 如果内部调用了 ctx.body 就会赋予值
        // 将结果响应回去
        if (!ctx.body) {
          res.end("Not Found");
        } else if (typeof ctx.body === "string") {
          res.end(ctx.body); // 此时还需要判断一下 ctx.body的类型
        } else if (ctx.body instanceof Stream) {
          ctx.body.pipe(res);
        } else if (typeof ctx.body === "object") {
          res.end(JSON.stringify(ctx.body));
        }
      })
      .catch((err) => {
        this.emit("error", err);
      });
  };
  listen(...args) {
    const server = http.createServer(this.handleRequest);
    server.listen(...args);
  }
};

// function create(obj) {
//   function Fn() {}
//   Fn.prototype = obj;
//   return new Fn();
// }
// let obj = { a: 1 };
// const copyObj1 = create(obj);
// copyObj1.b = 2;

// const copyObj2 = create(obj);
// console.log(copyObj2.a);
